package com.corgi.test.java8.time;

import lombok.extern.slf4j.Slf4j;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @title: NewLocalDateTime
 * @description:
 * @author: dengmiao
 * @create: 2019-11-15 13:06
 **/
@Slf4j
public class NewLocalDateTime {

    public static void main(String[] args) {
        // 从系统时钟获取LocalDateTime
        LocalDateTime now = LocalDateTime.now();
        log.info("现在是: .now() => {}", now);

        // 时间反格式化
        LocalDateTime ofNow = LocalDateTime.of(2019, Month.NOVEMBER, 15, 13, 07);
        LocalDateTime parseNow = LocalDateTime.parse("2019-11-15T13:07:21.987");
        log.info("现在是: .of() => {}, .parse() => {}", ofNow, parseNow);

        // 时间加减
        LocalDateTime nextDayPreHour = now.plusDays(1).minusHours(1);
        log.info("明天的一小时前是: {}", nextDayPreHour);

        DayOfWeek dayOfWeek = now.getDayOfWeek();
        int dayOfMonth = now.getDayOfMonth(), year = now.getYear(), dayOfYear = now.getDayOfYear();
        Month month = now.getMonth();
        int hour = now.getHour(), minute = now.getMinute(), second = now.getSecond(), nano = now.getNano();
        log.info("现在是: {}[{}], {}[{}], 一年的第{}天, 当月的第{}天, {}年, {}月, {}日, {}时, {}分, {}秒, {}毫微秒",
                dayOfWeek, dayOfWeek.getValue(), month, month.getValue(), dayOfYear, dayOfMonth, year, month.getValue(),
                dayOfMonth, hour, minute, second, nano);

        // 罗列所有时区
        Set<String> allZoneIds = ZoneId.getAvailableZoneIds();
        // log.info("{}", allZoneIds);
        // 筛选亚洲的时区
        Set<String> asiaZoneIds = allZoneIds.stream().filter(item -> item.indexOf("Asia") != -1).collect(Collectors.toSet());
        log.info("亚洲的时区: {}, 世界范围的时区总计{}个", asiaZoneIds, allZoneIds.size());

        ZoneId zoneId = ZoneId.of("Asia/Shanghai");
        log.info("这里是:{}", zoneId.getRules());

        LocalDateTime ldt = LocalDateTime.now(zoneId);
        log.info("现在是亚洲/上海 东八区时间:{}", ldt);

        // LocalDateTime转化为特定的时区中的时间：
        ZonedDateTime zdtOf = ZonedDateTime.of(ldt, zoneId);
        log.info("转换时区 .of() => {}", zdtOf);

        ZonedDateTime zdtParse = ZonedDateTime.parse(zdtOf.toString()/*"2019-11-15T13:07:21+08:00[Asia/Shanghai]"*/);
        log.info("转换时区 .parse() => {}", zdtParse);

        // 日期和时间字段，精确到纳秒，以及从UTC/格林威治的偏移量
        ZoneOffset offset = ZoneOffset.of("+02:00");
        OffsetDateTime offSetByTwo = OffsetDateTime.of(now, offset);
        log.info("{}", offSetByTwo.toZonedDateTime().getZone());

        // Period和Duration
        // Period : 用于计算两个日期（年月日）间隔。
        // Duration : 用于计算两个时间（秒，纳秒）间隔。

        LocalDate initialDate = LocalDate.parse("2019-11-15");
        LocalDate finalDate = initialDate.plus(Period.ofDays(5));
        // 计算两个日期的差
        int diffDate1 = Period.between(finalDate, initialDate).getDays();
        // 或者这样计算时间差
        long diffDate2 = ChronoUnit.DAYS.between(finalDate , initialDate);
        log.info("两日期差: {} {}", diffDate1, diffDate2);

        LocalTime initialTime = LocalTime.of(6, 30, 0);
        LocalTime finalTime = initialTime.minus(Duration.ofSeconds(30));
        long diffTime1 = Duration.between(finalTime, initialTime).getSeconds();
        long diffTime2 = ChronoUnit.SECONDS.between(finalTime, initialTime);
        log.info("两时间差: {} {}", diffTime1, diffTime2);

        // 日期转化
        Date date = new Date();
        Instant instant = date.toInstant();
        ZoneId defaultZoneId = ZoneId.systemDefault();
        Calendar calendar = Calendar.getInstance();
        LocalDateTime ofDate = LocalDateTime.ofInstant(instant, defaultZoneId);
        LocalDateTime ofCalendar = LocalDateTime.ofInstant(calendar.toInstant(), defaultZoneId);
        log.info("dateToLocalDateTime => {}, calendarToLocalDateTime => {}, 时间戳 => {}, 系统预设时区 => {}", ofDate, ofCalendar, instant, defaultZoneId);

        // 按UTC/格林威治的偏移量偏移纳秒
        LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(instant.getEpochSecond(), 0, ZoneOffset.UTC);
        log.info("时间戳+时间偏移{}", localDateTime);

        // 时间格式化
        String localDateISOString = localDateTime.format(DateTimeFormatter.ISO_DATE);
        String localDatePatternString = localDateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        String localDateUKString = localDateTime
                .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
                        .withLocale(Locale.UK));
        String localDateCNString = localDateTime
                .format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)
                        .withLocale(Locale.CANADA));
        log.info("{} {} {} {}", localDateISOString, localDatePatternString, localDateUKString, localDateCNString);



        /*Instant：它代表的是时间戳，表示时刻，不直接对应年月日信息，需要通过时区转换
        LocalDateTime: 表示与时区无关的日期和时间信息，不直接对应时刻，需要通过时区转换
        LocalDate：表示与时区无关的日期，与LocalDateTime相比，只有日期信息，没有时间信息
        LocalTime：表示与时区无关的时间，与LocalDateTime相比，只有时间信息，没有日期信息
        ZonedDateTime： 表示特定时区的日期和时间
        ZoneId/ZoneOffset：表示时区*/
    }
}
